package com.ddxz.demo.shiro.jwt.tool;

import com.alibaba.fastjson.JSONObject;
import com.ddxz.demo.shiro.jwt.JwtApplication;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.ibatis.cache.Cache;
import org.yaml.snakeyaml.Yaml;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * class description
 *
 * @author 朱宗刚
 * @version 1.0.0
 * @date 2020/12/2
 */

public class DdxzMybatisRedisCache implements Cache {
    @Override
    public String getId() {
        return this.id;
    }

    private String id;

    /**
     * mapper接口的类名
     * @param id
     */
    public DdxzMybatisRedisCache(final String id) {
        this.id = id;
        cache.put(id, new HashMap<>());
        loadConfig();
    }

    private void loadConfig() {
        client = new RedisClientInfo();
        Yaml yml = new Yaml();
        InputStream is = JwtApplication.class.getClassLoader().getResourceAsStream("application.yml");
        JSONObject properties = yml.loadAs(is, JSONObject.class);
        properties = properties.getJSONObject("spring").getJSONObject("redis");
        client.setClientName(properties.get("client-name").toString());
        client.setDatabase(properties.get("database").toString());
        client.setHost(properties.get("host").toString());
        client.setPassword(properties.get("password").toString());
        client.setPort(properties.get("port").toString());
        client.setSsl(properties.get("ssl").toString());
        client.setTimeout(properties.get("timeout").toString());
    }

    public synchronized void postInit() {
        pool = new JedisPool(new GenericObjectPoolConfig(),client.getHost(), client.getPort(), client.getTimeout(), client.getPassword(), client.getDatabase(), client.getClientName(), client.getSsl());
    }

    @Override
    public void putObject(Object key, Object value) {
        if(null == pool) {
            postInit();
        }

        if(null == value) {
            return;
        }

//        Jedis jedis = pool.getResource();
//        try {
//            jedis.hset(id.getBytes(), DdxzSerialize.serialize(key), DdxzSerialize.serialize(value));
//        } finally {
//            jedis.close();
//        }
        try (Jedis jedis = pool.getResource()) {
            jedis.hset(id.getBytes(), DdxzSerialize.serialize(key), DdxzSerialize.serialize(value));
        }
    }

    /**
     * 从缓存中获取数据
     * @param key 有函数名（含类名），SQL语句，参数清单，SessionFactoryBean，缺省获取的最少记录数0，最大记录数Integer.MAX_VALUE(2147483647)
     * @return
     */
    @Override
    public Object getObject(Object key) {
        if(null == pool) {
            postInit();
        }

//        Jedis jedis = pool.getResource();
//        try {
//            return DdxzSerialize.unserialize(jedis.hget(id.getBytes(), DdxzSerialize.serialize(key)));
//        } finally {
//            jedis.close();
//        }
        try (Jedis jedis = pool.getResource()) {
            return DdxzSerialize.unserialize(jedis.hget(id.getBytes(), DdxzSerialize.serialize(key)));
        }
    }

    @Override
    public Object removeObject(Object key) {
        if(null == pool) {
            postInit();
        }

//        Jedis jedis = pool.getResource();
//        try {
//            return jedis.hdel(id.getBytes(), DdxzSerialize.serialize(key));
//        } finally {
//            // 如果不能及时关闭连接，会在多次请求之后产生死锁
//            jedis.close();
//        }
        ;
        try (Jedis jedis = pool.getResource()) {
            return jedis.hdel(id.getBytes(), DdxzSerialize.serialize(key));
        }
    }

    @Override
    public void clear() {
        if(null == pool) {
            postInit();
        }
        pool.getResource().del(id.getBytes());
    }

    @Override
    public int getSize() {
        if(null == pool) {
            postInit();
        }

//        Jedis jedis = pool.getResource();
//        try {
//            return jedis.hgetAll(id.getBytes()).size();
//        } finally {
//            jedis.close();
//        }

        try (Jedis jedis = pool.getResource()) {
            return jedis.hgetAll(id.getBytes()).size();
        }
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return lock;
    }

    private static JedisPool pool;

    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    private RedisClientInfo client;

    private static Map<String, Map<Object, Object>> cache = new HashMap<>();
}
